package saxion.sensorframework;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.sql.ResultSet;
import java.util.ArrayList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import saxion.sensorframework.db.dao.DaoSensor;
import saxion.sensorframework.structuur.Sensor;

/**
 * \brief Used for sensor related tasks
 * 
 * Classes provides function to convert xml document to object, Save data to file, save sensor and sensor data to database
 * 
 * @author Erik & Martijn
 *
 */
public class SensorProcessor {

	private static Logger logger = Logger.getLogger(SensorValidator.class.getName()); /**< logger  \sa SensorFramework::logger */
	private DaoSensor daoSensor; /**< DaoSensor used for database connection */
	
	
	/**
	 * Classe for processing sensors and sensor data
	 */
	public SensorProcessor()
	{
		initialize();
	}
	
	/**
	 * \brief initialize variables.
	 * 
	 * Creates DaoSensor \link saxion.sensorframework.db.dao.DaoSensor \endlink
	 */
	private void initialize()
	{
		try {
			daoSensor = new DaoSensor();
		} catch (Exception e) {
			logger.error("Unable to create DaoSensor");
			e.printStackTrace();
		}
	}
	
	/** 
	 * \brief Covert XML document to sensor Object.
	 * 
	 * Uses JAX-b to create \link saxion.sensorframework.structuur.Sensor \endlink object form the xml document. Provided to the function (xmllocation).
	 * 
	 * @param xmlLocation
	 * @return create sensor object
	 */
	public Sensor convertXMLtoObject(String xmlLocation)
	{
			Sensor sensor = null;
			try {
			File file = new File(xmlLocation);
			
			JAXBContext jaxbContext = JAXBContext.newInstance(Sensor.class);
			Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
			sensor = (Sensor) jaxbUnmarshaller.unmarshal(file);
			
			} catch (Exception e){ 
				e.printStackTrace();
			} 
			return sensor;
	}

	/**
	 * \brief Reads xml data to database
	 * 
	 * 
	 * Get sensor data field from the database. Sensor ID provide in the xml document.
	 * Use a DocumentBuilderFactory to read xml file and retrive the sensor data.
	 * After retrive the sensor data the data is write to the database.
	 * 
	 * @param xmlLocation
	 * @throws Exception if error occures ( No data is written to the database)
	 */
	public void readXMLtoDatabase(String xmlLocation) throws Exception
	{
        File stocks = new File(xmlLocation);
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc = dBuilder.parse(stocks);
        doc.getDocumentElement().normalize();

        // normalize text representation
        doc.getDocumentElement().normalize();
        
        NodeList nodes = doc.getElementsByTagName("sensordata");
        
        Element element = (Element) nodes.item(0);

        String id = getValue("id", element) ;
        logger.debug("SensorData id:" + id);
        
       NodeList data = element.getElementsByTagName("data");
       Element element1 =(Element) data.item(0); // data element
       
       ResultSet rs = daoSensor.getSensorDataTypes(Integer.parseInt(id));
       
       ArrayList<String> fieldNames = new ArrayList<String>();
      
       rs.next(); //eerste waarde is id;
        while (rs.next()) {
        	fieldNames.add(rs.getString("Field"));
        }
       
        ArrayList<Object> values = new ArrayList<Object>();
        
        for(int i=0; i < fieldNames.size()-1; i++)
        {
        	logger.debug("Field:"+fieldNames.get(i));
        	String value = getValue(fieldNames.get(i), element1);
        	logger.debug(" Value:"+ value);	
        	values.add(value);
        }
        daoSensor.addSensorData(Integer.parseInt(id), values);
	}
	
	/**
	 * \brief Get value from DOM element.
	 * 
	 * Retrieve value from DOM element provided.
	 * 
	 * @param tag
	 * @param element 
	 * @return Retrieve value  (NULL if not found)
	 */
	private static String getValue(String tag, Element element) {
		NodeList nodes = element.getElementsByTagName(tag).item(0).getChildNodes();
		Node node = (Node) nodes.item(0);
		return node.getNodeValue();
	}
	
	/**
	 * \brief Save bytes to file.
	 * 
	 * Writes byte[] array to file using BufferdOutputStream 
	 * @param data Byte array to write to the file
	 * @param file location and extension to the file. example temp/test.xml
	 */
	public void saveDataToFile(byte[] data, String file)
	{
		try {
	 		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
				
		 		bos.write(data);
		 		bos.flush();
		 		bos.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	
}
